/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/
#define OMEN_SOURCE 1

/// This Timer class implementation is only for Windows-operating systems
#ifdef _WINDOWS
#define OMEN_SOURCE 1

#include "OmenTimer.h"
#include <Windows.h>
#include <iostream>

using namespace Omen;

Timer::Timer() :
    m_bRunning(false),
    m_currentTime(0),
    m_previousTime(0),
    m_initialTime(0),
    m_elapsedTime(0)
{
    initialize();
}

Timer::~Timer()
{
}

///
/// <summary>Starts the timer</summary>
///
void Timer::start()
{
    m_bRunning = true;
}

///
/// <summary>Stops the timer. Clears the counters</summary>
///
void Timer::stop()
{
    m_bRunning = false;
    initialize();
}

///
/// <summary>Pauses the timer. Clears the counters</summary>
///
void Timer::pause()
{
    m_bRunning = false;
}

///
/// <summary>Initializes the timer, which clears the counters</summary>
///
void Timer::initialize()
{
    m_initialTime = 0;
    m_currentTime = 0;
    m_previousTime = 0;
    m_elapsedTime = 0;
    m_fTotalTime = 0;
    m_bTimerInitialized = false;
}

///
/// <summary>Returns true if the timer is running, false othersize</summary>
///
bool Timer::running()
{
    return m_bRunning;
}

///
/// <summary>Returns the current system timer frequency</summary>
///
inline INT64 Timer::frequency()
{
    INT64 frequency;
    QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&frequency));
    return frequency;
}

///
/// <summary>Returns the current system timer value</summary>
///
inline INT64 Timer::currentTime()
{
    INT64 time;
    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&time));
    if( m_initialTime == 0 )
        m_initialTime = time;
    return time;
}

///
/// <summary>Updates the total and elapsed time values</summary>
///
void Timer::updateElapsedTime()
{
    static const int MAX_SAMPLE_COUNT = 50;
    static float frameTimes[MAX_SAMPLE_COUNT];
    static float timeScale = 0.0f;
    static float actualElapsedTimeSec = 0.0f;
    static INT64 freq = 0;
    static int sampleCount = 0;
    static bool initialized = false;

    float elapsedTimeSec = 0.0f;

    if (!m_bTimerInitialized)
    {
        m_bTimerInitialized = true;
        freq = frequency();
        m_previousTime = currentTime();
        timeScale = 1.0f / freq;
    }

    m_currentTime = currentTime();

    elapsedTimeSec = (m_currentTime - m_previousTime) * timeScale;
    m_previousTime = m_currentTime;

    if (fabsf(elapsedTimeSec - actualElapsedTimeSec) < 1.0f)
    {
        memmove(&frameTimes[1], frameTimes, sizeof(frameTimes) - sizeof(frameTimes[0]));
        frameTimes[0] = elapsedTimeSec;

        if (sampleCount < MAX_SAMPLE_COUNT)
            ++sampleCount;
    }

    actualElapsedTimeSec = 0.0f;

    for (int i = 0; i < sampleCount; ++i)
        actualElapsedTimeSec += frameTimes[i];

    if (sampleCount > 0)
        actualElapsedTimeSec /= sampleCount;

    m_fElapsedTime = actualElapsedTimeSec;
    m_fTotalTime += m_fElapsedTime;
}

///
/// <summary>Returns the total time in seconds since the timer was started</summary>
///
Omen::Float Timer::totalTime()
{
    updateElapsedTime();
    return m_fTotalTime;
}

///
/// <summary>Returns the elapsed time in seconds since the last query of elapsed time</summary>
///
Omen::Float Timer::elapsedTime(bool initTime)
{
    if( initTime )
        updateElapsedTime();
    return m_fElapsedTime;
}

#endif // _WINDOWS

/// EOF